package file.sftp;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import com.jcraft.jsch.SftpException;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.apache.commons.lang3.StringUtils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * @author guoqf
 */
public class TarGzFileUtils {

    private static String ip = "10.1.198.67";
    private static int port = 22;

    private static String user = "ng4a";

    private static String pwd = "Wolf@2022";

    private static String remoteDir = "/home/ng4a/tsnTest";

    private static String sourcePath = "C:\\Users\\tsing\\Desktop\\新建文件夹";


    private static String sourceFile = "BOMC3120_appAcctList_IT4A7320_20230201094529_cb14c748f3544ad4bd68adc1fffad867_1.C001.json";

    private static String remoteFile = "testFile.tar.gz";

    public static void main(String[] args) {
        digestAndPack();
        downloadUnUnpack();
//        readSftpFiles(remoteDir, Collections.singletonList(remoteFile));
    }

    private static void digestAndPack() {
        File file = new File(sourcePath, sourceFile);
        String digestContent = MD5.create().digestHex(file);

        String digestName = file.getName().replace(".json", ".md5");

        File digestFile = new File(file.getParentFile(), digestName);
        FileUtil.writeString(digestContent, digestFile, StandardCharsets.UTF_8);

        String tarFileFullPath = sourcePath + "\\" + file.getName().replace(".json", ".tar.gz");
        File tarFile = new File(tarFileFullPath);
        tarPack(Arrays.asList(file, digestFile), tarFile);

        remoteFile = tarFile.getName();
        uploadTarGzFile(tarFileFullPath, remoteFile);
    }

    private static void uploadTarGzFile(String localFilePath, String remoteFileName) {
        RemoteFileInfo fileInfo = getRemoteFileInfo(remoteFileName);

        uploadData(fileInfo, localFilePath);
    }

    private static void downloadUnUnpack() {


        RemoteFileInfo fileInfo = getRemoteFileInfo(remoteFile);
        List<String> dataList = downloadData(fileInfo);

        System.out.println("下载json文件：");
//        System.out.println(dataList);
    }

    private static RemoteFileInfo getRemoteFileInfo(String remoteFile) {
        RemoteFileInfo fileInfo = new RemoteFileInfo();
        fileInfo.setFileServiceIp(ip);
        fileInfo.setFileServicePort(port);
        fileInfo.setFileServiceUser(user);
        fileInfo.setFileServicePwd(pwd);
        fileInfo.setFileDir(remoteDir);
        fileInfo.setFileNames(Collections.singletonList(remoteFile));
        return fileInfo;
    }


    public static String extractJsonFile(InputStream fi) throws IOException {

        try (BufferedInputStream bi = new BufferedInputStream(fi);
             GzipCompressorInputStream gzi = new GzipCompressorInputStream(bi);
             TarArchiveInputStream ti = new TarArchiveInputStream(gzi)) {

            ArchiveEntry entry;
            while ((entry = ti.getNextEntry()) != null) {

                // create a new path, zip slip validate
//                Path newPath = zipSlipProtect(entry, target);

                String name = entry.getName();
                if (name.endsWith(".json")) {

                    return IoUtil.read(ti, StandardCharsets.UTF_8);
                }

            }
        }

        return "";
    }

    public static TarGzFileContent extractTarGzFile(InputStream fi) throws IOException {
        TarGzFileContent gzFile = new TarGzFileContent();
        try (BufferedInputStream bi = new BufferedInputStream(fi);
             GzipCompressorInputStream gzi = new GzipCompressorInputStream(bi);
             TarArchiveInputStream ti = new TarArchiveInputStream(gzi)) {

            ArchiveEntry entry;
            while ((entry = ti.getNextEntry()) != null) {

                // create a new path, zip slip validate
//                Path newPath = zipSlipProtect(entry, target);

                String name = entry.getName();
                if (name.endsWith(".json")) {
                    gzFile.setData(StrUtil.str(IoUtil.readBytes(ti, false), StandardCharsets.UTF_8));
                }else if (name.endsWith(".md5")) {
                    gzFile.setDigest(StrUtil.str(IoUtil.readBytes(ti, false), StandardCharsets.UTF_8));
                }

            }
        }

        return gzFile;
    }

    private static void tarPack(List<File> targetFiles, File tarFile) {

        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tarFile)); GzipCompressorOutputStream gios = new GzipCompressorOutputStream(bos); TarArchiveOutputStream taos = new TarArchiveOutputStream(gios)) {
            for (File targetFile : targetFiles) {

                taos.putArchiveEntry(new TarArchiveEntry(targetFile, targetFile.getName()));

                FileUtil.writeToStream(targetFile, taos);
                taos.closeArchiveEntry();
            }
            taos.finish();

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }



    private static List<String> downloadData(RemoteFileInfo fileInfo) {
        TsnFileServer sftpUtil = new TsnFileServer(fileInfo.getFileServiceIp(), fileInfo.getFileServicePort(), fileInfo.getFileServiceUser(), fileInfo.getFileServicePwd());
        boolean connect = sftpUtil.connect();
        List<String> dataList = new ArrayList<>();
        if (connect) {
            try {
                System.out.println("SFTP服务器连接成功");
                List<String> fileNames = fileInfo.getFileNames();
                String fileDir = fileInfo.getFileDir();
                for (String fileName: fileNames) {
                    try (InputStream download = sftpUtil.download(fileName, fileDir)) {
                        TarGzFileContent tarGz = extractTarGzFile(download);
                        System.out.println("下载json文件成功");
                        System.out.println("摘要: "+tarGz.getDigest());

                        String data = tarGz.getData();
                        boolean b = validateDigest(data, tarGz.getDigest());
                        if (b) {
                            System.out.println("摘要验证成功");
                            dataList.add(data);

                        }else {
                            System.out.println("摘要验证失败");
                        }
//                        System.out.println(s);

                        /*System.out.println("删除文件");
                        sftpUtil.remove(fileName, fileDir);
                        System.out.println("删除文件成功");*/
                    } catch (SftpException e) {
                        throw new RuntimeException(e);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            } finally {
                sftpUtil.disconnect();
            }

        }else {
            System.out.println("SFTP服务器连接失败");
        }
        return dataList;
    }

    private static boolean validateDigest(String data, String digest) {
        return StringUtils.equals(MD5.create().digestHex(data), digest);
    }

    private static void uploadData(RemoteFileInfo fileInfo, String localFilePath) {
        TsnFileServer sftpUtil = new TsnFileServer(fileInfo.getFileServiceIp(), fileInfo.getFileServicePort(), fileInfo.getFileServiceUser(), fileInfo.getFileServicePwd());
        boolean connect = sftpUtil.connect();
        if (connect) {
            try {
                System.out.println("SFTP服务器连接成功");
                List<String> fileNames = fileInfo.getFileNames();
                String fileDir = fileInfo.getFileDir();
                for (String fileName: fileNames) {
                    try {

                        sftpUtil.upload(new File(localFilePath), fileName, fileDir);
                        System.out.println("上传tar.gz文件成功");

                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            } finally {
                sftpUtil.disconnect();
            }

        }else {
            System.out.println("SFTP服务器连接失败");
        }
    }
}
